﻿#region Copyright ©2008-2011, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: then $
// Last Changed Date     $LastChangedDate: 2009-06-09 09:28:29 +0200 (Tue, 09 Jun 2009) $
// Last Changed Revision $Rev: 185 $
//
// ====================================================================================================
#endregion

using System;
using System.IO;
using Tum.CollabXT.Resources;

namespace Tum.CollabXT
{
    /// <summary>
    /// Log used for internal status and error reporting.
    /// </summary>
    public class Log : IDisposable
    {
        /// <summary>
        /// Delegate representing a method to be called when a new log entry has been added.
        /// </summary>
        /// <param name="entry">The newly added entry.</param>
        /// <param name="timeAdded">Time the entry was added.</param>
        /// <param name="type">Type of the new entry.</param>
        public delegate void LogEntryAddedDelegate(string entry, DateTime timeAdded, LogEntryType type);

        /// <summary>
        /// Event that is called whenever a new log entry is added.
        /// </summary>
        public event LogEntryAddedDelegate LogEntryAdded;

        private StreamWriter _LogWriter;


        /// <summary>
        /// Number of warnings since the last call of ResetErrorAndWarningCounters.
        /// </summary>
        /// <seealso cref="ResetErrorAndWarningCounters"/>
        public int WarningCount
        {
            get { return _WarningCount; }
        }
        private int _WarningCount;

        /// <summary>
        /// Number of errors since the last call of ResetErrorAndWarningCounters.
        /// </summary>
        /// <seealso cref="ResetErrorAndWarningCounters"/>
        public int ErrorCount
        {
            get { return _ErrorCount; }
        }
        private int _ErrorCount;


        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="logFile">Path of the log file to be extended / created.</param>
        public Log(string logFile)
        {
            ResetErrorAndWarningCounters();

            _LogWriter = new StreamWriter(logFile, true);
            _LogWriter.WriteLine();
            _LogWriter.WriteLine();
            _LogWriter.WriteLine("===================================");
            _LogWriter.WriteLine("============= PET log =============");
            _LogWriter.WriteLine("== " + DateTime.Now.ToUniversalTime().ToString("r") + " ==");
            _LogWriter.WriteLine("===================================");
            _LogWriter.WriteLine();
            _LogWriter.Flush();
        }

        /// <summary>
        /// Disposes the log.
        /// </summary>
        public void Dispose()
        {
            Close();
        }

        /// <summary>
        /// Closes the log.
        /// </summary>
        public void Close()
        {
            if (_LogWriter != null)
            {
                _LogWriter.WriteLine();
                _LogWriter.WriteLine("===================================");
                _LogWriter.WriteLine("== " + DateTime.Now.ToUniversalTime().ToString("r") + " ==");
                _LogWriter.WriteLine("===================================");
                _LogWriter.Flush();

                _LogWriter.Close();
                _LogWriter.Dispose();

                _LogWriter = null;
            }
        }

        /// <summary>
        /// Sets WarningCount and ErrorCount to zero.
        /// </summary>
        public void ResetErrorAndWarningCounters()
        {
            _WarningCount = 0;
            _ErrorCount = 0;
        }

        /// <summary>
        /// Adds a new log entry.
        /// </summary>
        /// <param name="entry">Content of the new entry.</param>
        public void AddEntry(string entry)
        {
            AddEntry(entry, LogEntryType.Status);
        }

        /// <summary>
        /// Adds a new log entry having a special type.
        /// </summary>
        /// <param name="entry">Content of the new entry.</param>
        /// <param name="entryType">Type of the new entry.</param>
        public void AddEntry(string entry, LogEntryType entryType)
        {
            if (entryType == LogEntryType.Warning)
            {
                _LogWriter.WriteLine("-- " + Language.Log_Warning + ":");
                _WarningCount++;
            }

            if (entryType == LogEntryType.Error)
            {
                _LogWriter.WriteLine("-- " + Language.Log_Warning + ":");
                _ErrorCount++;
            }

            DateTime time = DateTime.Now;
            _LogWriter.WriteLine("[" + time.ToUniversalTime().ToString("T") + "] " + entry);
            _LogWriter.Flush();

            if (LogEntryAdded != null)
                LogEntryAdded(entry, time, entryType);
        }

        /// <summary>
        /// Adds an entry to the log and throws an CollabXTException afterwards.
        /// </summary>
        /// <param name="entry">Content of the new entry.</param>
        public void AddEntryAndThrowException(string entry)
        {
            AddEntry(entry, LogEntryType.Error);
            throw new CollabXTException(entry);
        }

        /// <summary>
        /// Adds a seperator to the log. This visually seperates two entries.
        /// </summary>
        public void AddSeparator()
        {
            AddEntry("===================================");
        }

        /// <summary>
        /// Checks whether an object is null. If so, the given message is added to the log and a CollabXTException is thrown.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objToBeChecked"></param>
        /// <param name="isNullLogEntry"></param>
        /// <returns></returns>
        public T NullCheck<T>(T objToBeChecked, string isNullLogEntry) where T : class
        {
            if (objToBeChecked == null)
                AddEntryAndThrowException(isNullLogEntry);
            return objToBeChecked;
        }
    }

    /// <summary>
    /// Log entry types.
    /// </summary>
    public enum LogEntryType
    {
        /// <summary>
        /// A normal entry.
        /// </summary>
        Status,

        /// <summary>
        /// A warning.
        /// </summary>
        Warning,

        /// <summary>
        /// An error.
        /// </summary>
        Error
    }
}
